package com.shelpe.services.simbasync.controller;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CompletionService;
import java.util.concurrent.ExecutorCompletionService;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import org.apache.commons.lang.math.NumberUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.context.request.async.DeferredResult;

import com.shelpe.services.simbasync.dto.KeywordsDto;
import com.shelpe.services.simbasync.dto.RptKeywordDto;
import com.shelpe.services.simbasync.exception.RequestParamException;
import com.shelpe.services.simbasync.model.Adgroups;
import com.shelpe.services.simbasync.model.Keywords;
import com.shelpe.services.simbasync.model.RptKeyword;
import com.shelpe.services.simbasync.model.Users;
import com.shelpe.services.simbasync.model.mongo.KeywordStrTemp;
import com.shelpe.services.simbasync.model.mongo.WordInsightMetric;
import com.shelpe.services.simbasync.service.AdgroupsService;
import com.shelpe.services.simbasync.service.AuthService;
import com.shelpe.services.simbasync.service.KeywordsService;
import com.shelpe.services.simbasync.service.SyncRecordService;
import com.shelpe.services.simbasync.service.UserService;
import com.shelpe.services.simbasync.service.simbaproxy.KeywordsProxy;
import com.shelpe.services.simbasync.service.simbaproxy.KeywordsProxy.Score;
import com.shelpe.services.simbasync.util.Util;


@RestController
@RequestMapping(value="/simbasync")
public class KeywordsController {
	
	private static final Logger logger = LoggerFactory.getLogger(KeywordsController.class);
	
	private static final Map<String, Date> requestPool = new HashMap<String, Date>();
	
	@Autowired
	private KeywordsService service;
	
	@Autowired
	private KeywordsProxy proxy;
	
	@Autowired
	private UserService user;
	
	@Autowired
	private AuthService auth;
	
	@Autowired
	private AdgroupsService adService;
	
	@Autowired
	private SyncRecordService syncService;
	
	private final ExecutorService executor = Executors.newFixedThreadPool(4);
	
	@RequestMapping("/tenants/{user}/adgroups/{adgroup_id}/@keyword")
	@ResponseBody
	public KeywordsDto syncKeywordsByUser(@PathVariable("user") String user, @PathVariable("adgroup_id") Long adgroupId){
		
		boolean isNumber = user.matches("-?[0-9]+.*[0-9]*");
		
		return isNumber ? syncKeywords(null, Long.valueOf(user), adgroupId) : syncKeywords(user, null, adgroupId);
	
	}
	
	@RequestMapping("/tenants/{user}/adgroups/{adgroup_id}/@keywordasyn")
	@ResponseBody
	public DeferredResult<KeywordsDto> syncKeywordsByUserAsyn(@PathVariable("user") final String user, @PathVariable("adgroup_id") final Long adgroupId){
		
		final DeferredResult<KeywordsDto> result = new DeferredResult<KeywordsDto>();
		final boolean isNumber = user.matches("-?[0-9]+.*[0-9]*");
		CompletionService<KeywordsDto> comletionService = new ExecutorCompletionService<KeywordsDto>(executor); 
		
		comletionService.submit(new Callable<KeywordsDto>(){
                                                                                                                                                                                                    
			@Override
			public KeywordsDto call() throws Exception {
				// TODO Auto-generated method stub
				KeywordsDto dto = null;
				if(isNumber){
					dto = syncKeywords(null, Long.valueOf(user), adgroupId);
				}else{
					dto = syncKeywords(user, null, adgroupId);
				}
				
				result.setResult(dto);
				
				return dto;
			}});
		
		return result;
	}
	
	@RequestMapping("/tenants/{user}/adgroups/{adgroup_id}/@keywordscore")
	@ResponseBody
	public KeywordsDto syncKeywordsScoreByUser(@PathVariable("user") String user, @PathVariable("adgroup_id") Long adgroupId){
		
		boolean isNumber = user.matches("-?[0-9]+.*[0-9]*");
		
		return isNumber ? syncKeywordsScore(null, Long.valueOf(user), adgroupId) : syncKeywordsScore(user, null, adgroupId);
	}
	
	@RequestMapping("/tenants/{user}/adgroups/{adgroup_id}/@keywordscoreasyn")
	@ResponseBody
	public DeferredResult<KeywordsDto> syncKeywordsScoreByUserAsyn(@PathVariable("user") final String user, @PathVariable("adgroup_id") final Long adgroupId){
		
		final DeferredResult<KeywordsDto> result = new DeferredResult<KeywordsDto>();
		final boolean isNumber = user.matches("-?[0-9]+.*[0-9]*");
		CompletionService<KeywordsDto> comletionService = new ExecutorCompletionService<KeywordsDto>(executor); 
		
		comletionService.submit(new Callable<KeywordsDto>(){
                                                                                                                                                                                                    
			@Override
			public KeywordsDto call() throws Exception {
				// TODO Auto-generated method stub
				KeywordsDto dto = null;
				if(isNumber){
					dto = syncKeywordsScore(null, Long.valueOf(user), adgroupId);
				}else{
					dto = syncKeywordsScore(user, null, adgroupId);
				}
				
				result.setResult(dto);
				
				return dto;
			}});
		
		return result;
	}
	
	@RequestMapping("/tenants/{user}/adgroups/{adgroup_id}/@keywordscorewireless")
	@ResponseBody
	public KeywordsDto syncKeywordsScoreByUserWirelessQScore(@PathVariable("user") String user, @PathVariable("adgroup_id") Long adgroupId){
		
		boolean isNumber = user.matches("-?[0-9]+.*[0-9]*");
		
		return isNumber ? syncKeywordsScoreWireless(null, Long.valueOf(user), adgroupId) : syncKeywordsScoreWireless(user, null, adgroupId);
	}
	
	@RequestMapping("/tenants/{user}/campaigns/{campaign_id}/adgroups/{adgroup_id}/@rptkeyword")
	@ResponseBody
	public RptKeywordDto syncRptKeywordsByUser(@PathVariable("user") String user, @PathVariable("campaign_id") Long campaignId, @PathVariable("adgroup_id") Long adgroupId,
			@RequestParam(value = "start_date", required = false) String startDate, @RequestParam(value = "end_date", required = false) String endDate, @RequestParam(value = "type", required = false) final String type,
			@RequestParam(value = "record", required = false) final String record){
		
		boolean isNumber = user.matches("-?[0-9]+.*[0-9]*");
		
		
		return isNumber ? syncRptKeywords(null, Long.valueOf(user), campaignId, adgroupId, startDate, endDate, type, record) : syncRptKeywords(user, null, campaignId, adgroupId, startDate, endDate, type, record);
		
	}
	
	@RequestMapping("/tenants/{user}/@rptkeywordneedsync")
	@ResponseBody
	public RptKeywordDto isNeedSyncRptKeywordsByUser(@PathVariable("user") String user){
		
		boolean isNumber = user.matches("-?[0-9]+.*[0-9]*");
	
		return isNumber ? needSyncRptKeywords(null, Long.valueOf(user)) : needSyncRptKeywords(user, null);
		
	}
	
	@RequestMapping("/tenants/{user}/campaigns/{campaign_id}/adgroups/{adgroup_id}/@rptkeywordrange")
	@ResponseBody
	public RptKeywordDto getSyncRptKeywordsRange(@PathVariable("user") String user, @PathVariable("campaign_id") Long campaignId, @PathVariable("adgroup_id") Long adgroupId){
		
		boolean isNumber = user.matches("-?[0-9]+.*[0-9]*");	
		
		return isNumber ? syncRptKeywordsRange(null, Long.valueOf(user), campaignId, adgroupId) : syncRptKeywordsRange(user, null, campaignId, adgroupId);
		
		
	}
	
	@RequestMapping("/tenants/{user}/campaigns/{campaign_id}/adgroups/{adgroup_id}/@rptkeywordasyn")
	@ResponseBody
	public DeferredResult<RptKeywordDto> syncRptKeywordsByUserAsyn(@PathVariable("user") final String user, @PathVariable("campaign_id") final Long campaignId, @PathVariable("adgroup_id") final Long adgroupId,
			@RequestParam(value = "start_date", required = false) final String startDate, @RequestParam(value = "end_date", required = false) final String endDate, @RequestParam(value = "type", required = false) final String type,
			@RequestParam(value = "record", required = false) final String record){
		
		final DeferredResult<RptKeywordDto> result = new DeferredResult<RptKeywordDto>();
		final boolean isNumber = user.matches("-?[0-9]+.*[0-9]*");
		CompletionService<RptKeywordDto> comletionService = new ExecutorCompletionService<RptKeywordDto>(executor); 
		
		comletionService.submit(new Callable<RptKeywordDto>(){
                                                                                                                                                                                                    
			@Override
			public RptKeywordDto call() throws Exception {
				// TODO Auto-generated method stub
				RptKeywordDto dto = null;
				if(isNumber){
					dto = syncRptKeywords(null, Long.valueOf(user), campaignId, adgroupId, startDate, endDate, type, record);
				}else{
					dto = syncRptKeywords(user, null, campaignId, adgroupId, startDate, endDate, type, record);
				}
				
				result.setResult(dto);
				
				return dto;
			}});
		
		return result;
	}
	
	@RequestMapping("/tenants/{user}/adgroups/{adgroup_id}/@insightkeyworddata")
	@ResponseBody
	public RptKeywordDto syncInsightKeywordDataByUser(@PathVariable("user") String user, @PathVariable("adgroup_id") Long adgroupId, @RequestParam("keywordstr") String keywordstr){
		
		boolean isNumber = user.matches("-?[0-9]+.*[0-9]*");
		
		return isNumber ? syncInsightKeywordData(null, Long.valueOf(user), adgroupId, keywordstr) : syncInsightKeywordData(user, null, adgroupId, keywordstr);
		
	}
	
	@RequestMapping("/@keywordstr")
	@ResponseBody
	public KeywordsDto deleteKeywordStrTempByEndDate(){
		
		KeywordsDto dto = new KeywordsDto();
	
		dto.setProcess("deleteKeywordStr");
		Date beginProcessTime = new Date();

		Map<String, String> dateMap = Util.getTaskRange();
			
		Date endDateFormat = new Date();
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		
		try{
			endDateFormat = sdf.parse(dateMap.get("endDate"));
			
		}catch(ParseException e) {
				// TODO Auto-generated catch block
			e.printStackTrace();
		}
		
		service.deleteByScopeEndTime(endDateFormat);
		
		Date endProcessTime = new Date();
		long durTime = endProcessTime.getTime() - beginProcessTime.getTime();
		
		dto.setDurTime(durTime);
		
		return dto;
	}
	
	@RequestMapping("/tenants/{user}/adgroups/{adgroup_id}/@keywordstr")
	@ResponseBody
	public KeywordsDto filterKeywordsByUser(@PathVariable("user") String users, @PathVariable("adgroup_id") Long adgroupId){
		
		boolean isNumber = users.matches("-?[0-9]+.*[0-9]*");
		Long userId = null;
		
		if(isNumber){
			userId = Long.valueOf(users);
		}else{
			userId = user.getUserIdByNick(users);
		}
	       
		if(userId == null){
			logger.warn("nick or userId is null, do nothing");
			throw new RequestParamException();
		}
		
		logger.info("filterKeywordsByUser userId {}, adgroupId {}", userId, adgroupId);
		
		KeywordsDto dto = new KeywordsDto();
		dto.setUserId(userId);
		dto.setProcess("filterKeywordsByUser");
		String userIdStr = userId.toString();
		Date beginProcessTime = new Date();
			
		if(!service.existKeywordsTable(userIdStr)){
			
			service.createKeywordsTable(userIdStr);
		}
		
		List<Keywords> list = service.getKeywordsByAdGroupId(userIdStr, adgroupId);
		
		List<KeywordStrTemp> keywordTemp = new ArrayList<KeywordStrTemp>();
		for(Keywords word : list){
			
			KeywordStrTemp temp = service.getKeywordStrTempByWord(word.getWord());
			if(temp == null){
				List<Long> keywordIDs = new ArrayList<Long>();
				List<Long> adgroupIDs = new ArrayList<Long>();
				temp = new KeywordStrTemp();
				temp.setKeywordIDs(keywordIDs);
				temp.setAdgroupIDs(adgroupIDs);
				temp.setUserId(userId);
				temp.setWord(word.getWord());
			}
			
			temp.getKeywordIDs().add(word.getKeywordId());
			temp.getAdgroupIDs().add(word.getAdgroupId());
			keywordTemp.add(temp);	
		}
		
		if(keywordTemp.size() > 0){
			service.saveKeywordStrTempList(keywordTemp);
			dto.setAddNum(keywordTemp.size());
		}
		
		Date endProcessTime = new Date();
		long durTime = endProcessTime.getTime() - beginProcessTime.getTime();
		dto.setDurTime(durTime);
		
		return dto;
	}
	
	@RequestMapping("/tenants/@keywordtable")
	@ResponseBody
	public int alterKeywordsTable(){
		List<Users> list = user.getAllUsers();
		int num = 0;
		for(Users user : list){
			String userIdStr = user.getUserId().toString();
	
			if(service.existKeywordsTable(userIdStr)){
					
				service.alterKeywordsTable(userIdStr);
				
				num++;
				logger.info("alterKeywordsTable  {}", num);
			}
		}
		
		return num;
	}
	
	@RequestMapping("/tenants/@rptkeywordtable")
	@ResponseBody
	public int alterRptKeywordsTable(){
		List<Users> list = user.getAllUsers();
		int num = 0;
		for(Users user : list){
			String userIdStr = user.getUserId().toString();
			
			if(service.existRptKeywordsTable(userIdStr)){
					
				service.alterRptKeywordsTable(userIdStr);
	
				num++;
				logger.info("alterRptKeywordsTable  {}", num);
			}
		}
		
		return num;
	}
	
	/****************************************************************************/

	private KeywordsDto syncKeywords(String nick, Long userId, Long adgroupId){
		
		
		if(userId == null){
			userId = user.getUserIdByNick(nick);
		}
		
		if(nick == null){
			nick = user.getNickByUserId(userId);
		}
	       
		if(nick == null || userId == null){
			logger.warn("nick or userId is null, do nothing");
			throw new RequestParamException();
		}
		logger.info(">>>syncKeywords nick {}, userId {}, adgroupId {}", nick, userId, adgroupId);
		KeywordsDto dto = new KeywordsDto();
		dto.setNick(nick);
		dto.setUserId(userId);
		dto.setProcess("syncKeywords");
        String userIdStr = userId.toString();
		Date beginProcessTime = new Date();
		
		String requestParam = Util.createKey(null, userId.toString(), null, adgroupId.toString(), null);
		if(requestPool.containsKey(requestParam)){
			
			Date lastProcessDate = requestPool.get(requestParam);
			if(beginProcessTime.getTime() - lastProcessDate.getTime() > Util.MilliSecondsOfMin * 2){
				requestPool.remove(requestParam);
				logger.info(">>>syncKeywords nick {}, userId {}, adgroupId {}, process out time, restart new sync task", nick, userId, adgroupId);
			}else{
				dto.setMessage("On processing");
				logger.info(">>>syncKeywords nick {}, userId {}, adgroupId {}, request too freq", nick, userId, adgroupId);
				return dto;
			}
		}

		requestPool.put(requestParam, beginProcessTime);	
		
		String response = null;
		try{
			response = proxy.getKeywordsByAdGroupId(nick, adgroupId);
		}catch(Exception e){
			logger.warn("Maybe something is wrong or can not find token, userId {}", userId);
		}
	
		if(response != null && response.contains("isv.invalid-permission")){//没有权限
			dto.setMessage("invalid-permission");
			requestPool.remove(requestParam);
			return dto;
		}else if(response != null && response.contains("invalid-sessionkey")){
			dto.setMessage("invalid-sessionkey");
			logger.warn("can not get any info from proxy, maybe something is wrong, nick is {}, response {}", nick, response);
			requestPool.remove(requestParam);
			return dto;
		}else if(response == null){
			dto.setMessage("get no information");
			requestPool.remove(requestParam);
			return dto;
		}
		
		List<Keywords> list = null;
		try{
			list = service.parseJsonToKeywords(response);
			service.updateKeywordsData(userIdStr, list);
			
		}catch(Exception e){
			requestPool.remove(requestParam);
			throw e;
		}
	
		if(!service.existKeywordsTable(userIdStr)){
				
			service.createKeywordsTable(userIdStr);
		}
			
		List<Keywords> oldListTemp = service.getKeywordsByAdGroupId(userIdStr, adgroupId);
			
		List<Keywords> oldList = new ArrayList<Keywords>();
			
		if(oldListTemp != null){
			oldList.addAll(oldListTemp);
		}
			
		Map<String, List<Keywords> > splitKeywords = service.splitKeywords(list, oldList);
		dto.setAddNum(service.insertKeywordsBatch(userIdStr, splitKeywords.get("add")));
		dto.setUpdateNum(service.updateKeywordsList(userIdStr, splitKeywords.get("update")));
		dto.setDeleteNum(service.deleteKeywordsList(userIdStr, splitKeywords.get("delete")));
		
		Date endProcessTime = new Date();
		long durTime = endProcessTime.getTime() - beginProcessTime.getTime();
		dto.setDurTime(durTime);
		
		requestPool.remove(requestParam);
		
		return dto;
	}
	
	private KeywordsDto syncKeywordsScore(String nick, Long userId, Long adgroupId){
		
		if(userId == null){
			userId = user.getUserIdByNick(nick);
		}
		
		if(nick == null){
			nick = user.getNickByUserId(userId);
		}
	       
		if(nick == null || userId == null){
			logger.warn("nick or userId is null, do nothing");
			throw new RequestParamException();
		}
		logger.info(">>>syncKeywordsScore nick {}, userId {}, adgroupId {}", nick, userId, adgroupId);
		KeywordsDto dto = new KeywordsDto();
		dto.setNick(nick);
		dto.setUserId(userId);
		dto.setProcess("syncKeywordsScore");
		String userIdStr = userId.toString();
		
		if(!service.existKeywordsTable(userIdStr)){
			
			service.createKeywordsTable(userIdStr);
		}
		
		if(!service.existRptKeywordsTable(userIdStr)){
			
			service.createRptKeywordsTable(userIdStr);
		}
		
		Date beginProcessTime = new Date();
		
		List<Keywords> keywords = service.getKeywordsByAdGroupId(userIdStr, adgroupId);
		
		if(keywords != null && keywords.size() > 0){
			List<Score> scoreList = new ArrayList<Score>();
			List<Keywords> result = service.getKeywordIdsScore(nick, adgroupId, keywords, scoreList);
			Date lastDate = service.getLastTimeFromRptScore(userId.toString(), adgroupId);
			Date dateNow = new Date();
			dateNow = Util.getYYYYMMDD(dateNow);
			
			if(lastDate == null || lastDate.getTime() < dateNow.getTime()){
				
				service.insertRptKeywordScore(userId.toString(), scoreList);
			}
			
			dto.setUpdateNum(service.updateKeywordsList(userIdStr, result));
		}
		
		Date endProcessTime = new Date();
		long durTime = endProcessTime.getTime() - beginProcessTime.getTime();
		dto.setDurTime(durTime);
		
		return dto;
	}

	private KeywordsDto syncKeywordsScoreWireless(String nick, Long userId, Long adgroupId){
		
		if(userId == null){
			userId = user.getUserIdByNick(nick);
		}
		
		if(nick == null){
			nick = user.getNickByUserId(userId);
		}
	       
		if(nick == null || userId == null){
			logger.warn("nick or userId is null, do nothing");
			throw new RequestParamException();
		}
		logger.info(">>>syncKeywordsScoreWireless nick {}, userId {}, adgroupId {}", nick, userId, adgroupId);
		KeywordsDto dto = new KeywordsDto();
		dto.setNick(nick);
		dto.setUserId(userId);
		dto.setProcess("syncKeywordsScore");
		String userIdStr = userId.toString();
		
		if(!service.existKeywordsTable(userIdStr)){
			
			service.createKeywordsTable(userIdStr);
		}
		
		Date beginProcessTime = new Date();
		
		List<Keywords> keywords = service.getKeywordsByWirelessQscore(userIdStr, adgroupId);
		
		if(keywords != null && keywords.size() > 0){
			List<Score> scoreList = new ArrayList<Score>();
			List<Keywords> result = service.getKeywordIdsScore(nick, adgroupId, keywords, scoreList);
			dto.setUpdateNum(service.updateKeywordsList(userIdStr, result));
		}
		
		Date endProcessTime = new Date();
		long durTime = endProcessTime.getTime() - beginProcessTime.getTime();
		dto.setDurTime(durTime);
		
		return dto;
	}
	
	private RptKeywordDto needSyncRptKeywords(String nick, Long userId){
		
		if(userId == null){
			userId = user.getUserIdByNick(nick);
		}
		
		if(nick == null){
			nick = user.getNickByUserId(userId);
		}
	       
		if(nick == null || userId == null){
			logger.warn("nick or userId is null, do nothing");
			throw new RequestParamException();
		}
		
		RptKeywordDto dto = new RptKeywordDto();
		dto.setNick(nick);
		dto.setUserId(userId);
		dto.setProcess("needSyncRptKeywords");
		Date beginProcessTime = new Date();  
		
		List<Adgroups> adList = adService.getAdgroupsByUserId(userId);
		
		boolean needSync = false;
		if(adList != null && adList.size() > 0){
			needSync = true;
			logger.info(">>>needSyncRptKeywords userId {}, adList size {}", userId, adList.size());
			for(Adgroups ad : adList){
				Long campaignId = ad.getCampaignId();
				Long adgroupId = ad.getAdgroupId();
				Map<String, List<Long>> dateRange = new HashMap<String, List<Long>>();
				Map<String, String> map = parseDateRange(userId, campaignId, adgroupId, null, null, dateRange);
				if(map.get("startTime").compareTo(map.get("endTime")) > 0){//不需要同步
					needSync = false;
				}
			}
		}
		
		dto.setNeedSync(needSync);
		logger.info(">>>needSyncRptKeywords userId {}, needSync {}", userId, needSync);
		Date endProcessTime = new Date();
		
		long durTime = endProcessTime.getTime() - beginProcessTime.getTime();
		dto.setDurTime(durTime);
		
		return dto;
	}

	private RptKeywordDto syncRptKeywordsRange(String nick, Long userId, Long campaignId, Long adgroupId){
		
		if(userId == null){
			userId = user.getUserIdByNick(nick);
		}
		
		if(nick == null){
			nick = user.getNickByUserId(userId);
		}
	       
		if(nick == null || userId == null){
			logger.warn("nick or userId is null, do nothing");
			throw new RequestParamException();
		}
		
		RptKeywordDto dto = new RptKeywordDto();
		dto.setNick(nick);
		dto.setUserId(userId);
		dto.setProcess("syncRptKeywordsRange");
		Date beginProcessTime = new Date(); 
		
		
		String userIdStr = userId.toString();
		if(!service.existRptKeywordsTable(userIdStr)){
				
			service.createRptKeywordsTable(userIdStr);
		}
		
		Map<String, List<Long>> dateRange = new HashMap<String, List<Long>>();
		Map<String, String> map = parseDateRange(userId, campaignId, adgroupId, null, null, dateRange);
		dto.setNeedSync(false);
		logger.info(">>> startTime {}, endTime {}, pageSize {}", map.get("startTime"), map.get("endTime"), map.get("pageSize"));
		if(map.get("startTime").compareTo(map.get("endTime")) < 1){//需要同步
			dto.setStartDate(map.get("startTime"));
			dto.setEndDate(map.get("endTime"));
			dto.setNeedSync(true);
		}
	
		Date endProcessTime = new Date();
		
		long durTime = endProcessTime.getTime() - beginProcessTime.getTime();
		dto.setDurTime(durTime);
		
		return dto;
	}
	private RptKeywordDto syncRptKeywords(String nick, Long userId, Long campaignId, Long adgroupId, String startDate, String endDate, String type, String record){
		
		if(userId == null){
			userId = user.getUserIdByNick(nick);
		}
		
		if(nick == null){
			nick = user.getNickByUserId(userId);
		}
	       
		if(nick == null || userId == null){
			logger.warn("nick or userId is null, do nothing");
			throw new RequestParamException();
		}
		logger.info(">>>syncRptKeywords nick {}, userId {}, campaignId {} ,adgroupId {}", nick, userId, campaignId,adgroupId);
		RptKeywordDto dto = new RptKeywordDto();
		dto.setNick(nick);
		dto.setUserId(userId);
		dto.setProcess("syncRptKeywords");
		Date beginProcessTime = new Date();      
		
		String requestParam = Util.createKey("rpt", userId.toString(), campaignId.toString(), adgroupId.toString(), endDate);
		if(requestPool.containsKey(requestParam)){
			
			Date lastProcessDate = requestPool.get(requestParam);
			if(beginProcessTime.getTime() - lastProcessDate.getTime() > Util.MilliSecondsOfMin * 5){
				requestPool.remove(requestParam);
				logger.info(">>>syncRptKeywords nick {}, userId {}, campaignId {}, adgroupId {}, process out time, restart new sync task", nick, userId, campaignId, adgroupId);
			}else{
				dto.setMessage("On processing");
				logger.info(">>>syncRptKeywords nick {}, userId {}, campaignId {}, adgroupId {}, request too freq", nick, userId, campaignId, adgroupId);
				return dto;
			}
		}

		requestPool.put(requestParam, beginProcessTime);	
		
		
		String userIdStr = userId.toString();
		if(!service.existRptKeywordsTable(userIdStr)){
				
			service.createRptKeywordsTable(userIdStr);
		}
		
		Map<String, List<Long>> dateRange = new HashMap<String, List<Long>>();
		Map<String, String> map = parseDateRange(userId, campaignId, adgroupId, startDate, endDate, dateRange);
		
		logger.info(">>> startTime {}, endTime {}, pageSize {}", map.get("startTime"), map.get("endTime"), map.get("pageSize"));
		if(map.get("startTime").compareTo(map.get("endTime")) < 1){//需要同步
			
			String subwayToken = auth.getSubwayTokenByUserId(userId);
			
			if(subwayToken == null){
				logger.warn("can not find subwaytoken, nick is {}, campaign_id is {}", nick, campaignId);
				dto.setMessage("can not find subwaytoken");
				requestPool.remove(requestParam);
				return dto;
			}
			
			String source = "1,2,4,5";
			String searchType = "SEARCH,CAT,NOSEARCH";
			int pageSize = 5000;
			pageSize = NumberUtils.toInt(map.get("pageSize"), 5000);
	
			String response = null;
			
			int pageNo = 1;
			List<RptKeyword> listTotal = new ArrayList<RptKeyword>();
			List<RptKeyword> subList = null;
			
			try{
				
				do{
					response = proxy.getRptAdgroupKeywordBase(subwayToken, nick, campaignId, adgroupId, source, searchType, map.get("startTime"), map.get("endTime"), pageSize, pageNo);
					
					if(response != null && response.contains("isv.invalid-permission")){//没有权限
						dto.setMessage("invalid-permission");
						requestPool.remove(requestParam);
						return dto;
					}else if(response != null && response.contains("invalid-sessionkey")){
						dto.setMessage("invalid-sessionkey");
						logger.warn("can not get any info from proxy, maybe something is wrong, nick is {}, response {}", nick, response);
						requestPool.remove(requestParam);
						return dto;
					}else if(response == null){
						dto.setMessage("get no information");
						requestPool.remove(requestParam);
						return dto;
					}
					
					subList = service.parseJsonToRptKeywordBase(response);
					if(subList != null && subList.size() > 0){
						listTotal.addAll(subList);
					}
					pageNo++;
				}while(subList != null && subList.size() == pageSize && pageSize > 0);
			
				int restSize = 0; 
				//int totalEffect = 0;
				pageNo = 1;
				if(listTotal != null && listTotal.size() > 0 && pageSize > 0){
					int lastDayRecordTotal = 0;
					int lastDayNoDataNum = 0;
					do{
						response = proxy.getRptAdgroupKeywordEffect(subwayToken, nick, campaignId, adgroupId, source, searchType, map.get("startTime"), map.get("endTime"), pageSize, pageNo);		
						Map<String, Integer> lastDayRecord = new HashMap<String, Integer>();
						restSize = service.combineRptKeywordEffect(response, lastDayRecord, listTotal);	
						lastDayRecordTotal += lastDayRecord.get("total");
						lastDayNoDataNum += lastDayRecord.get("lost");
						//totalEffect+=restSize;
						pageNo++;
					}while(restSize == pageSize);
					
					if(record != null && record.equalsIgnoreCase("yes") 
							&& lastDayRecordTotal > 0 && lastDayNoDataNum == lastDayRecordTotal){//有基础数据，没有效果数据

						Date lastDate = Util.getLastDayYYYYMMDD();
						long lastCustRpt = user.countRptCustomerByUserIdDate(userId, lastDate);
						if(lastCustRpt == 0){
							
							logger.warn("syncRptKeyword, base data num {}, effect data num is zero, adgroupId is {}", listTotal.size(), adgroupId);
							syncService.updateSyncRecordByProcess("syncRptKeyword", 1);
							dto.setMessage("last day has no data yet");
							requestPool.remove(requestParam);
							
							return dto;
						}
					}
					
					service.updateRptKeywordData(userIdStr, listTotal);
				}
				
			}catch(Exception e){
				requestPool.remove(requestParam);
				throw e;
			}
			
			if(startDate != null && endDate != null && type == null){
				deleteRptDataByDateRange(userIdStr, dateRange);
			}
			
			dto.setAddNum(service.insertRptKeywordsBatch(userIdStr, listTotal));
	
		}
		Date endProcessTime = new Date();
		
		long durTime = endProcessTime.getTime() - beginProcessTime.getTime();
		dto.setDurTime(durTime);
		
		requestPool.remove(requestParam);
		
		return dto;
	}
	
	private RptKeywordDto syncInsightKeywordData(String nick, Long userId, Long adgroupId, String keywordstr){
		
		if(userId == null){
			userId = user.getUserIdByNick(nick);
		}
		
		if(nick == null){
			nick = user.getNickByUserId(userId);
		}
	       
		if(nick == null || userId == null){
			logger.warn("nick or userId is null, do nothing");
			throw new RequestParamException();
		}
		logger.info(">>>syncInsightKeywordData nick {}, userId {}, adgroupId {}", nick, userId, adgroupId);
		RptKeywordDto dto = new RptKeywordDto();
		dto.setNick(nick);
		dto.setUserId(userId);
		dto.setProcess("syncInsightKeywordData");
		Date beginProcessTime = new Date();      
		String userIdStr = userId.toString();

		if(!service.existKeywordsTable(userIdStr)){
			
			service.createKeywordsTable(userIdStr);
		}
		
		Set<String> wordSet = new HashSet<String>();
		Map<String, String> dateMap = Util.getTaskRange();
		
		if(keywordstr != null && (!keywordstr.equals("")) && (!keywordstr.equals("null"))){//不过滤
			
			String[] wordStr = keywordstr.split(",");
			for(int i = 0; i < wordStr.length; i++){
				wordSet.add(wordStr[i]);
			}
		}else{
			
			List<Keywords> keywords = service.getKeywordsByAdGroupId(userIdStr, adgroupId);
			Set<String> wordSetAll = new HashSet<String>();
			if(keywords != null && keywords.size() > 0){
				for(Keywords item : keywords){
					wordSetAll.add(item.getWord());
				}
			}
			
			Date endDateFormat = new Date();
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			try {
				endDateFormat = sdf.parse(dateMap.get("endDate"));
			} catch (ParseException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			for(String word : wordSetAll){
				if(!service.existsByWordAndScopeEndTime(word, endDateFormat)){
					wordSet.add(word);
				}
			}
		}
		
		List<String> words = new ArrayList<String>(wordSet);
		
		List<WordInsightMetric> data = service.getInsightWordData(userId, dateMap.get("startDate"), dateMap.get("endDate"), words);
  
		if(data != null && data.size() > 0){
			service.saveInsightWordData(data); 
			dto.setAddNum(data.size());
		}

		Date endProcessTime = new Date();
		
		long durTime = endProcessTime.getTime() - beginProcessTime.getTime();
		
		dto.setDurTime(durTime);
		
		return dto;
	}

	/************辅助函数******************/
	
	private Map<String, String> parseDateRange(Long userId, Long campaignId,Long adgroupId, String startDate, String endDate, Map<String, List<Long>> dateRange){
		
		Integer pageSize = 5000;
	
		Map<String, String> map = null;
		if(startDate == null || endDate == null){
			Date dateOld = service.getLastTimeFromRpt(userId.toString(), campaignId, adgroupId); 
			map = Util.getDateRange(dateOld);
			startDate = map.get("startTime");
			endDate = map.get("endTime");
			pageSize = NumberUtils.toInt(map.get("pageSize"), 5000);
		}
	
		if(startDate.compareTo(endDate) < 1){
			StringBuilder sb = new StringBuilder();
			sb.append(startDate);
			sb.append(",");
			sb.append(endDate);
			String range = sb.toString();
			if(dateRange.containsKey(range)){
				dateRange.get(range).add(adgroupId);
			}else{
				List<Long> idsList = new ArrayList<Long>();
				idsList.add(adgroupId);
				dateRange.put(range, idsList);
			}
		}
		
		if(map == null){
			map = new HashMap<String, String>();
			map.put("startTime", startDate);
			map.put("endTime", endDate);
			map.put("pageSize", pageSize.toString());
		}
		
		return map;
	}
	
	private void deleteRptDataByDateRange(String userId, Map<String, List<Long>> dateRange){
		
		for(Map.Entry<String, List<Long>> entry : dateRange.entrySet()){
			
			String key = entry.getKey();
			String[] range = key.split(",");
			Date startDate = new Date();
			Date endDate = startDate;
			SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
			try {
				startDate = sdf.parse(range[0]);
				endDate = sdf.parse(range[1]);
			} catch (ParseException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		
			List<Long> adgroupIds = entry.getValue();
			service.deleteRptKeywordsByDateRange(userId, adgroupIds, startDate, endDate);
		}
	}

}